﻿using Orleans.EventSourcing;
using Orleans.Providers;

namespace orleans_demo.Services
{
    [LogConsistencyProvider(ProviderName = "LogStorage")]
    [StorageProvider(ProviderName = "SnapshotStore")] // 需要同时标注存储提供程序
    public class LogGrain : JournaledGrain<AccountState, AccountEvent>, ILogGrain
    {
        public async Task Deposit(decimal amount)
        {
            if (amount <= 0)
                throw new ArgumentException("Deposit amount must be positive");
            // 1. 触发存款事件
            RaiseEvent(new DepositedEvent(amount, DateTime.UtcNow));
            // 2. 持久化事件到事件存储
            await ConfirmEvents();
        }

        public async Task Withdraw(decimal amount)
        {
            if (amount <= 0)
                throw new ArgumentException("Withdrawal amount must be positive");

            if (State.Balance < amount)
                throw new InvalidOperationException("Insufficient funds");

            RaiseEvent(new WithdrawnEvent(amount, DateTime.UtcNow));
            await ConfirmEvents();
        }

        public Task<decimal> GetBalance() => Task.FromResult(State.Balance);

        public Task<string> GetHistory()
        {
            var history = $"Account {this.GetPrimaryKey()} history:\n";
            history += $"Current balance: {State.Balance}\n";
            history += $"Last transaction: {State.LastTransactionDate}\n";
            return Task.FromResult(history);
        }

        // 应用事件到状态
        protected override void OnStateChanged()
        {
            // 可以在这里添加状态变更后的逻辑
            Console.WriteLine($"Account {this.GetPrimaryKey()} state updated. New balance: {State.Balance}");
        }

        protected override void TransitionState(AccountState state, AccountEvent @event)
        {
            switch (@event)
            {
                case DepositedEvent deposited:
                    state.Balance += deposited.Amount;
                    state.LastTransactionDate = deposited.Timestamp;
                    break;

                case WithdrawnEvent withdrawn:
                    state.Balance -= withdrawn.Amount;
                    state.LastTransactionDate = withdrawn.Timestamp;
                    break;
            }
        }
    }

}
